One of the design goals of all Macintosh System Software is to provide "plug-and-play" hardware installation. For example, to install a screen on your Macintosh, you simply plug in the Nubus board, wire it to your monitor, and boot up the computer. QuickTime adds this "plug-and-play" simplicity for video digitizers, which convert a video image (such as from a VCR or video camera) into some machine readable form (such as a PICT). Why would you want to digitize a video image? For all the same reasons that you would want to scan an image with a scanner; the main difference is that the type of importable imagery is not bits of paper, but anything that exists as video.
Recently, I was writing a small application that required the use of a video digitizer card. This application required only the very simplest of digitizing operations: “Capture a single frame, now, please.” QuickTime defines a standard interface for video digitizing cards; however, this interface is very complex, and allows each digitizer card considerable flexibility as to which features are or aren’t implemented. QuickTime therefore provides a component called the “Sequence Grab” component, which simplifies the interface to video digitizers, by handling offscreen buffering, and scaling, and a myriad other details. But, the “Sequence Grab” component was still too complex for my tastes, and didn’t have my desired “Capture a single frame, now, please” command.
So, after much gnashing of teeth and keyboard, I came up with a very tiny little library of routines that simply grabs a single frame of video into the current GrafPort, into a requested rectangle. This library should be helpful to you, the Macintosh programmer with an interest in QuickTime and video, in two ways. One: you may be able to use it just as it is for some simple applications. Two: you can follow the easy-to-read source code and see exactly what are the minimal steps necessary to grab a video frame, using the “Sequence Grab” component.
Two files are needed: “BigEasyVideoGrabber.h” and “BigEasyVideoGrabber.c.” You’ll need to include the ‘.h file in your sources to use these routines. You’ll need to compile and link your code with the ‘.c file.
This routine locates a video digitizer card, and initializes it, and returns a pointer to a structure called an “EasyVideoGrabber,” which you’ll pass to the other two routines in the library. If there is more than one digitizer in the Macintosh, then you cannot specify which is used.
The rectangle, “outputSize,” is filled in with the bounds of the video frame that the digitizer can return. For example, a full-resolution digitizer might return the rectangle (0,0,640,480), while a low-resolution device might only be (0,0,160,120).
If “nil” is returned, there was some problem with using a video digitizer. A common reason for a “nil” return is that the Macintosh has no video digitizer.
This routine grabs a single frame of video into the current GrafPort, and scales it to fit into the rectangle specified by “r”. “evg” may either be an EasyVideoGrabber that was previously opened by “NewEasyVideoGrabber”, or may be “nil”, in which case one is opened, a frame captured from it, and immediately closed. The disadvantage of passing “nil” is that it is slightly slower, and you cannot determine the video digitizer resolution.
When an “EasyVideoGrabber” is no longer needed, it should be disposed with this routine. This will free up the associated hardware for use by other clients.
Example Of Use
The following routine shows the simplest possible use of the EasyVideoGrabber routines. The fragment assumes that a GrafPort has been set up to draw into. This code is incorporated into a complete Macintosh application, in the sample file, “EasyGrabberTest.c”.
void ASimpleDigitizingExample(void)
{
/*
* Set the rectangle we'll be drawing into.
*/
SetRect(&r,0,0,160,120);
/*
* Let the user click five times
* and grab a frame each time.
*
* This is a somewhat substandard user interface,
* I am sure you will agree.
*/
for(i = 0; i < 5; i++)
{
/*
* Wait For A MouseClick
*/
while(!Button());
while(Button());
/*
* Grab a frame into the current GrafPort
* allocate and deallocate on the fly.
*/
gotAFrame = GrabEasyVideoGrabber(nil,&r);
/*
* If we didn't get a frame, just quit and go home.
*/
if(!gotAFrame)
return;
}
}
Conclusion
If you’re writing the Great Macintosh Video Digitizing Application, you’ll probably want to perform the spleen-curdling task of accessing each video digitizer component directly. But if you want to grab some pixels from a digitizer right now, then this little library should be just the ticket.